/* 
* Copyright (C) 2005, 2006 Liu Di <liudidi@gmail.com> 
*
* Copyright (C) 2007 Wei Lian <lianwei3@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "sound.h"

#ifdef ALSA

Sound::Sound (QObject * parent, const char *name):
QObject (parent, name)
{
   assert (snd_mixer_open (&handle, 0) >= 0);
   snd_mixer_attach (handle, "default");
   snd_mixer_selem_register (handle, NULL, NULL);
   snd_mixer_load (handle);

   ///alsa mixer init
   elem = NULL;
   for (snd_mixer_elem_t * var = snd_mixer_first_elem (handle); var;
	var = snd_mixer_elem_next (var))
      if (strcasecmp ("PCM", snd_mixer_selem_get_name (var)) == 0) {
	 elem = var;
	 break;
      }
      else if (strcasecmp ("Master", snd_mixer_selem_get_name (var)) == 0) {
	 elem = var;
      }
   assert (elem);
   ///dealing with alsa bug
   long int a, b;
   snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, &a);
   snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_RIGHT, &b);
   ///set volume range
   long min, max;
   snd_mixer_selem_get_playback_volume_range (elem, &min, &max);
   snd_mixer_selem_set_playback_volume_range (elem, 0, 100);

}

Sound::~Sound ()
{
   if (handle)
      snd_mixer_close (handle);
}


int
Sound::volume ()
{
   long ll, lr;
   snd_mixer_handle_events (handle);
   snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, &ll);
   snd_mixer_selem_get_playback_volume (elem,
					SND_MIXER_SCHN_FRONT_RIGHT, &lr);
   return (ll + lr) >> 1;
}

void
Sound::volume (int leftright)
{
   snd_mixer_selem_set_playback_volume (elem,
					SND_MIXER_SCHN_FRONT_LEFT, leftright);
   snd_mixer_selem_set_playback_volume (elem,
					SND_MIXER_SCHN_FRONT_RIGHT,
					leftright);
}

#else

Sound::Sound (QObject * parent, const char *name):
QObject (parent, name)
{
   if ((handle = open ("/dev/mixer", O_RDWR, 0)) == -1) {
      ::perror ("/dev/mixer");
   }
}

Sound::~Sound ()
{
   ::close (handle);
}

int
Sound::volume ()
{
   int result;
   if (::ioctl (handle, MIXER_READ (4), &result) == -1) {
      ::perror ("read_error");
      return -1;
   }
   result = ((result >> 8) + (result & 0xFF)) >> 1;
   result = (result > 0) ? result : 0;
   result = (result < 100) ? result : 100;
   return result;
}

void
Sound::volume (int leftright)
{
   leftright = (leftright < 0) ? 0 : leftright;
   leftright = (leftright > 100) ? 100 : leftright;
   leftright = (leftright << 8) | (leftright & 0xFF);
   if (::ioctl (handle, MIXER_WRITE (4), &leftright) == -1) {
      perror ("write_error");
      return;
   }
}

#endif
